package com.wonders;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import static java.lang.Thread.sleep;

/**
 * Servlet是单例多线程的，servlet容器在初始化Servlet时会为每一个Servlet创建一个
 * 线程池，当请求到来时，servlet会从线程池中获取一个线程去执行，然后等待着这个线程的执行结果，
 * 最终将结果返回给客户端
 */
@WebServlet("/AsyncServlet2")
public class AsyncServlet2 extends HttpServlet {
    /**
     * 首先Servlet已经从线程池中取一个线程来执行这个请求了，只要这个线程没执行完，Servlet就会一直等待，
     * 那我们在另外创建一个线程去执行这个耗时的任务，然后让Servlet的那个线程执行结束。
     * 这段代码的执行结果是：客户端浏览器不需要等待这这个耗时的任务执行完就可以立即看到一个响应结果，任务在
     * 后台被执行。
     *
     * 异步确实是异步了，但是在页面上并没有子线程out.append里的内容，这是因为主线程很快就结束了，主线程
     * 结束，意味着out内容已经输出到客户端，response结束，在此之后在往out添加内容，就无效了，因为整个交互
     * 已经结束。
     *
     * 我们如何在子线程里把子线程的执行信息输出到客户端？有两种方式：
     *  1、在主线程中等待子线程执行结果，如下，使用join。打开join代码注释，使用join，客户端需要长时间等待。
     *  2、使用AsyncContext，参见AsyncServlet3
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.append("主线程开始运行<br>");
        Thread t = new Thread(() -> {
            out.append("子线程开始运行<br>");
            // 我要执行一个很耗时的操作
            try {
                for (int i = 0; i < 8; i++) {
                    System.out.println("i == " + i);
                    out.append("i == " + i + "<br>");
                    sleep(1000);
                }
            } catch (InterruptedException e) {
                System.out.println(e);
            }
            out.append("子线程运行结束<br>");
        });
        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        out.append("主线程运行结束<br>");
    }
}
